package com.lg.algorithm.collections.map;

import lombok.SneakyThrows;

import java.util.HashMap;
import java.util.Iterator;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * 遍历的过程不能 修改map
 * modCount字段主要用来记录HashMap内部结构发生变化的次数，主要用于迭代的快速失败
 */
public class HashMapModify {
    @SneakyThrows
    public static void main(String[] args) throws InterruptedException {
        /**
         * 在遍历 hashmap 的时候，这个hashmap发生了变换，那么这个遍历应该抛出异常，这叫做线程安全
         *
         * 使用迭代器变量hashmap的时候，是线程安全的。发改变hashmap，会触发ConcurrentModificationException  Fail-Fast机制。原理是当进入迭代器的时候会
         * 记录这个map的 modCount 每次取值的时候会比较这个值是否发生变化。强调一点，内部结构发生变化指的是结构发生变化，例如put新键值对，
         * 但是某个key对应的value值被覆盖不属于结构变化。
         *
         * 迭代器 和 普通的遍历 都能保证在自己遍历的时候， 自己改变的异常
         * 但迭代器，还能保证在自己遍历的时候， 别人改变的异常
         * 普通的遍历不会
         */

        /**
         * for (Object o : hashMap.keySet())  和
         * Iterator iterator = hashMap.keySet().iterator() 效果相同
         */
//        fun1();
//        fun2();
//        fun3();
//        fun4();

        fun5();

    }

    @SneakyThrows
    public static void fun5() {
        HashMap hashMap = new HashMap<String, Integer>();
        CountDownLatch countDownLatch = new CountDownLatch(2);
        int num = 10;
        for (int i = 0; i < num; i++) {
            hashMap.put(String.valueOf(i), i);
        }

        Thread thread = new Thread(() -> {
            System.out.println("thread start");
            try {
                for (int i = 0; i < hashMap.size(); i++) {
                    System.out.println(i + " --> " + hashMap.get(String.valueOf(i)));
                    countDownLatch.countDown();
                    countDownLatch.await();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("thread over");
        });
        thread.start();

        TimeUnit.SECONDS.sleep(1);

        //自己遍历的时候 他人不可以 删除
        hashMap.remove("0");
        hashMap.remove("5");

        //自己遍历的时候 他人可以 增加
        hashMap.put("11", 11);

        //自己遍历的时候 他人可以 修改
        hashMap.put("1", 11);

        countDownLatch.countDown();
    }

    @SneakyThrows
    public static void fun4() {
        HashMap hashMap = new HashMap<String, Integer>();
        CountDownLatch countDownLatch = new CountDownLatch(2);
        int num = 10;
        for (int i = 0; i < num; i++) {
            hashMap.put(String.valueOf(i), i);
        }

        Thread thread = new Thread(() -> {
            System.out.println("thread start");
            try {
                for (Object o : hashMap.keySet()) {
                    System.out.println(o.toString() + " --> " + hashMap.get(o.toString()));
                    countDownLatch.countDown();
                    countDownLatch.await();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("thread over");
        });
        thread.start();

        TimeUnit.SECONDS.sleep(1);

        //自己遍历的时候 他人不可以 删除
//        hashMap.remove("0");
//        hashMap.remove("5");

        //自己遍历的时候 他人不可以 增加
//        hashMap.put("11", 11);

        //自己遍历的时候 他人可以 修改
        hashMap.put("1", 11);

        countDownLatch.countDown();
    }


    @SneakyThrows
    public static void fun3() {
        HashMap hashMap = new HashMap<String, Integer>();
        CountDownLatch countDownLatch = new CountDownLatch(2);
        int num = 10;
        for (int i = 0; i < num; i++) {
            hashMap.put(String.valueOf(i), i);
        }

        Thread thread = new Thread(() -> {
            System.out.println("thread start");
            try {
                Iterator iterator = hashMap.keySet().iterator();
                while (iterator.hasNext()) {
                    Object key = iterator.next();
                    System.out.println(key + " --> " + hashMap.get(key));
                    countDownLatch.countDown();
                    countDownLatch.await();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("thread over");
        });
        thread.start();

        TimeUnit.SECONDS.sleep(1);

        //自己遍历的时候 他人不可以 删除
//        hashMap.remove("0");
//        hashMap.remove("5");

        //自己遍历的时候 他人不可以 增加
//        hashMap.put("11", 11);

        //自己遍历的时候 他人可以 修改
        hashMap.put("1", 11);

        countDownLatch.countDown();
    }

    public static void fun2() {
        HashMap hashMap = new HashMap<String, Integer>();
        for (int i = 0; i < 10; i++) {
            hashMap.put(String.valueOf(i), i);
        }

        for (Object o : hashMap.keySet()) {
            System.out.println(o + " --> " + hashMap.get(o.toString()));

            if (o.toString().equals("0")) {
//               自己遍历的时候 不可以 删除
//                hashMap.remove("0");

                //自己遍历的时候 不可以 增加
//                hashMap.put("11", 11);


                //自己遍历的时候可以 修改
                hashMap.put("1", 11);
            }
        }

        System.out.println("----------------");
        for (Object o : hashMap.keySet()) {
            System.out.println(o + " --> " + hashMap.get(o.toString()));
        }
    }

    public static void fun1() {
        HashMap hashMap = new HashMap<String, Integer>();
        for (int i = 0; i < 10; i++) {
            hashMap.put(String.valueOf(i), i);
        }
        Iterator iterator = hashMap.keySet().iterator();

        while (iterator.hasNext()) {
            Object key = iterator.next();
            System.out.println(hashMap.get(key));
            if (key.toString().equals("0")) {
                //自己遍历的时候 不可以 删除
//                hashMap.remove("0");

                //自己遍历的时候 不可以 增加
//                hashMap.put("11", 11);


                //自己遍历的时候 可以 通过自己删除
                iterator.remove();
                //自己遍历的时候可以 修改
                hashMap.put("1", 11);
            }
        }
        System.out.println("----------------");
        for (Object o : hashMap.keySet()) {
            System.out.println(o + " --> " + hashMap.get(o.toString()));
        }

    }


}
